﻿using MsTestUtilities.Errors;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MsTestUtilities.Utilities;

namespace MsTestUtilities.RowTests
{
    public class TestScenarioBuilder<T1, E>
    {		
		private Func<T1, E> _methodUnderTest;
		private TestCaseCollection<T1, E> _testCases;
		private Action _setup = () => {};

		public TestCaseCollection<T1, E> For(Func<T1, E> methodUnderTest)
		{
			_methodUnderTest = methodUnderTest;
			_testCases = new TestCaseCollection<T1, E>(this);		
			return _testCases;
		}

		public TestScenarioBuilder<T1, E> WithSetup(Action setup)
		{
			_setup = setup;
			return this;
		}

		public void Evaluate()
		{
			var errorCollector = new ErrorCollector();
			var testNr = 0;
			int testNrLength = _testCases.Count().ToString().Length;
			foreach(var testCase in _testCases)
			{
				testNr++;
				_setup();
				var result = testCase.IsSatisfiedFor(_methodUnderTest);
				if (!result.AssertionHolds)
				{
					var error = string.Format("Test Case {0}: {1} {2}", 
						Pad(testNrLength, testNr),
						result.AssertionError, 
						testCase.Justification.GetJustification());
					errorCollector.AddError(error);
				}
			}

			errorCollector.Evaluate();
		}

		private string Pad(int size, int number)
		{
			var printNumber = number.ToString();
			var padding = size - printNumber.Length;
			return new string('0', padding) + printNumber;
		}
    }

    public class TestScenarioBuilder<T1, T2, E>
    {		
		private Func<T1, T2, E> _methodUnderTest;
		private TestCaseCollection<T1, T2, E> _testCases;
		private Action _setup = () => {};

		public TestCaseCollection<T1, T2, E> For(Func<T1, T2, E> methodUnderTest)
		{
			_methodUnderTest = methodUnderTest;
			_testCases = new TestCaseCollection<T1, T2, E>(this);		
			return _testCases;
		}

		public TestScenarioBuilder<T1, T2, E> WithSetup(Action setup)
		{
			_setup = setup;
			return this;
		}

		public void Evaluate()
		{
			var errorCollector = new ErrorCollector();
			var testNr = 0;
			int testNrLength = _testCases.Count().ToString().Length;
			foreach(var testCase in _testCases)
			{
				testNr++;
				_setup();
				var result = testCase.IsSatisfiedFor(_methodUnderTest);
				if (!result.AssertionHolds)
				{
					var error = string.Format("Test Case {0}: {1} {2}", 
						Pad(testNrLength, testNr),
						result.AssertionError, 
						testCase.Justification.GetJustification());
					errorCollector.AddError(error);
				}
			}

			errorCollector.Evaluate();
		}

		private string Pad(int size, int number)
		{
			var printNumber = number.ToString();
			var padding = size - printNumber.Length;
			return new string('0', padding) + printNumber;
		}
    }

    public class TestScenarioBuilder<T1, T2, T3, E>
    {		
		private Func<T1, T2, T3, E> _methodUnderTest;
		private TestCaseCollection<T1, T2, T3, E> _testCases;
		private Action _setup = () => {};

		public TestCaseCollection<T1, T2, T3, E> For(Func<T1, T2, T3, E> methodUnderTest)
		{
			_methodUnderTest = methodUnderTest;
			_testCases = new TestCaseCollection<T1, T2, T3, E>(this);		
			return _testCases;
		}

		public TestScenarioBuilder<T1, T2, T3, E> WithSetup(Action setup)
		{
			_setup = setup;
			return this;
		}

		public void Evaluate()
		{
			var errorCollector = new ErrorCollector();
			var testNr = 0;
			int testNrLength = _testCases.Count().ToString().Length;
			foreach(var testCase in _testCases)
			{
				testNr++;
				_setup();
				var result = testCase.IsSatisfiedFor(_methodUnderTest);
				if (!result.AssertionHolds)
				{
					var error = string.Format("Test Case {0}: {1} {2}", 
						Pad(testNrLength, testNr),
						result.AssertionError, 
						testCase.Justification.GetJustification());
					errorCollector.AddError(error);
				}
			}

			errorCollector.Evaluate();
		}

		private string Pad(int size, int number)
		{
			var printNumber = number.ToString();
			var padding = size - printNumber.Length;
			return new string('0', padding) + printNumber;
		}
    }

    public class TestScenarioBuilder<T1, T2, T3, T4, E>
    {		
		private Func<T1, T2, T3, T4, E> _methodUnderTest;
		private TestCaseCollection<T1, T2, T3, T4, E> _testCases;
		private Action _setup = () => {};

		public TestCaseCollection<T1, T2, T3, T4, E> For(Func<T1, T2, T3, T4, E> methodUnderTest)
		{
			_methodUnderTest = methodUnderTest;
			_testCases = new TestCaseCollection<T1, T2, T3, T4, E>(this);		
			return _testCases;
		}

		public TestScenarioBuilder<T1, T2, T3, T4, E> WithSetup(Action setup)
		{
			_setup = setup;
			return this;
		}

		public void Evaluate()
		{
			var errorCollector = new ErrorCollector();
			var testNr = 0;
			int testNrLength = _testCases.Count().ToString().Length;
			foreach(var testCase in _testCases)
			{
				testNr++;
				_setup();
				var result = testCase.IsSatisfiedFor(_methodUnderTest);
				if (!result.AssertionHolds)
				{
					var error = string.Format("Test Case {0}: {1} {2}", 
						Pad(testNrLength, testNr),
						result.AssertionError, 
						testCase.Justification.GetJustification());
					errorCollector.AddError(error);
				}
			}

			errorCollector.Evaluate();
		}

		private string Pad(int size, int number)
		{
			var printNumber = number.ToString();
			var padding = size - printNumber.Length;
			return new string('0', padding) + printNumber;
		}
    }

    public class TestScenarioBuilder<T1, T2, T3, T4, T5, E>
    {		
		private Func<T1, T2, T3, T4, T5, E> _methodUnderTest;
		private TestCaseCollection<T1, T2, T3, T4, T5, E> _testCases;
		private Action _setup = () => {};

		public TestCaseCollection<T1, T2, T3, T4, T5, E> For(Func<T1, T2, T3, T4, T5, E> methodUnderTest)
		{
			_methodUnderTest = methodUnderTest;
			_testCases = new TestCaseCollection<T1, T2, T3, T4, T5, E>(this);		
			return _testCases;
		}

		public TestScenarioBuilder<T1, T2, T3, T4, T5, E> WithSetup(Action setup)
		{
			_setup = setup;
			return this;
		}

		public void Evaluate()
		{
			var errorCollector = new ErrorCollector();
			var testNr = 0;
			int testNrLength = _testCases.Count().ToString().Length;
			foreach(var testCase in _testCases)
			{
				testNr++;
				_setup();
				var result = testCase.IsSatisfiedFor(_methodUnderTest);
				if (!result.AssertionHolds)
				{
					var error = string.Format("Test Case {0}: {1} {2}", 
						Pad(testNrLength, testNr),
						result.AssertionError, 
						testCase.Justification.GetJustification());
					errorCollector.AddError(error);
				}
			}

			errorCollector.Evaluate();
		}

		private string Pad(int size, int number)
		{
			var printNumber = number.ToString();
			var padding = size - printNumber.Length;
			return new string('0', padding) + printNumber;
		}
    }

    public class TestScenarioBuilder<T1, T2, T3, T4, T5, T6, E>
    {		
		private Func<T1, T2, T3, T4, T5, T6, E> _methodUnderTest;
		private TestCaseCollection<T1, T2, T3, T4, T5, T6, E> _testCases;
		private Action _setup = () => {};

		public TestCaseCollection<T1, T2, T3, T4, T5, T6, E> For(Func<T1, T2, T3, T4, T5, T6, E> methodUnderTest)
		{
			_methodUnderTest = methodUnderTest;
			_testCases = new TestCaseCollection<T1, T2, T3, T4, T5, T6, E>(this);		
			return _testCases;
		}

		public TestScenarioBuilder<T1, T2, T3, T4, T5, T6, E> WithSetup(Action setup)
		{
			_setup = setup;
			return this;
		}

		public void Evaluate()
		{
			var errorCollector = new ErrorCollector();
			var testNr = 0;
			int testNrLength = _testCases.Count().ToString().Length;
			foreach(var testCase in _testCases)
			{
				testNr++;
				_setup();
				var result = testCase.IsSatisfiedFor(_methodUnderTest);
				if (!result.AssertionHolds)
				{
					var error = string.Format("Test Case {0}: {1} {2}", 
						Pad(testNrLength, testNr),
						result.AssertionError, 
						testCase.Justification.GetJustification());
					errorCollector.AddError(error);
				}
			}

			errorCollector.Evaluate();
		}

		private string Pad(int size, int number)
		{
			var printNumber = number.ToString();
			var padding = size - printNumber.Length;
			return new string('0', padding) + printNumber;
		}
    }

}
